﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.IO;
using System.IO.Compression;
using System.Text.RegularExpressions;
using ICSharpCode.SharpZipLib.Zip;
using System.Windows;
using System.ComponentModel; 

namespace CtxPublishTool
{
    public class MainWindowModel : INotifyPropertyChanged
    {
        #region Ctor
        public MainWindowModel()
        { 
            ZipFileFormat = "Publish_{0}_{1}.zip";
            PrepareSetupCommand = new DelegateCommand(OnPrepareSetup);
            CompressFilesCommand = new DelegateCommand(OnCompressFiles);
            PrepareUploadtoGoldCommand = new DelegateCommand(OnPrepareUploadtoGold);
            SetupSitesCommand = new DelegateCommand(OnSetupSites);
            ZipFiles = new List<string>();
            Status = "N/A";
        }
        #endregion

        #region Properties
        public string ZipFileFormat
        {
            get;
            private set;
        }
        public IList<string> ZipFiles
        {
            get;
            set;
        }

        private string status = string.Empty;
        public string Status
        {
            get
            {
                return status;
            }
            set
            {
                status = value;
                OnPropertyChanged("Status");
            }
        }
        #endregion

        #region PrepareSetupCommand
        public ICommand PrepareSetupCommand { get; set; }
        public void OnPrepareSetup(object parameter)
        {
            PrepareSetup();
        }
        #endregion

        #region CompressFilesCommand
        public ICommand CompressFilesCommand { get; set; }
        public void OnCompressFiles(object parameter)
        {
            CompressFiles();
        }
        #endregion

        #region CopytoGoldPathCommand
        public ICommand PrepareUploadtoGoldCommand { get; set; }
        public void OnPrepareUploadtoGold(object parameter)
        {
            PrepareUploadtoGold();
        }
        #endregion

        #region SetupSitesCommand
        public ICommand SetupSitesCommand { get; set; }
        public void OnSetupSites(object parameter)
        {
            SetupSites();
        }
        #endregion

        #region AllInOneCommand
        public ICommand AllInOneCommand { get; set; }
        public void OnAllInOne(object parameter)
        {
            PrepareSetup();
            SetupSites();

            CompressFiles();
            PrepareUploadtoGold();
        }
        #endregion

        #region Helper Methods
        private void EnsureDirectoryExists(string directoryPath)
        {
            if (!Directory.Exists(directoryPath))
            {
                Directory.CreateDirectory(directoryPath);
            }
        }

        private void PrepareSetup()
        {
            // CMS6.
            var cms6AppBinPath = Path.Combine(Configuration.Current.CMS6AppPath, "bin");
            var allCms6AppFiles = Directory.GetFiles(cms6AppBinPath);
            foreach (var file in allCms6AppFiles)
            {
                Status = string.Format("Copy File: {0}", file);
                File.Copy(file, file.Replace(Configuration.Current.CMS6AppPath, Configuration.Current.CMS6PublishPath), true);
            }

            // VCMS.
            var vcmsAppBinPath = Path.Combine(Configuration.Current.VCMSAppPath, "bin");
            var allVcmsAppFiles = Directory.GetFiles(vcmsAppBinPath);
            foreach (var file in allVcmsAppFiles)
            {
                Status = string.Format("Copy File: {0}", file);
                File.Copy(file, file.Replace(Configuration.Current.VCMSAppPath, Configuration.Current.VCMSPublishPath), true);
            }

            // All Components
            var components = Directory.GetDirectories(Configuration.Current.ComponentsPublishPath);
            foreach (var component in components)
            {
                var binPath = Path.Combine(component, "bin");
                var componentName = new DirectoryInfo(component).Name;
                var componentDllFileName = string.Format("Vision.Cms.MvcComponents.{0}.dll", componentName);
                var files = Directory.GetFiles(binPath);
                foreach (var file in files)
                {
                    if (Path.GetFileName(file) != componentDllFileName)
                    {
                        Status = string.Format("Remove File: {0}", file);
                        File.Delete(file);
                    }
                }

                var subDirectories = Directory.GetDirectories(binPath);
                foreach (var subDirectory in subDirectories)
                {
                    Status = string.Format("Remove Folder: {0}", subDirectory);
                    Directory.Delete(subDirectory, true);
                }
            }
            MessageBox.Show("Files are ready.");
        }

        private void CompressFiles()
        {
            var zip = new FastZip();

            // CMS6
            CompressFolder(zip, Configuration.Current.CMS6PublishPath);

            // Components
            CompressFolder(zip, Configuration.Current.ComponentsPublishPath);

            // VCMS
            CompressFolder(zip, Configuration.Current.VCMSPublishPath);

            MessageBox.Show("Compress File Successfully.");
        }

        private void CompressFolder(FastZip zip, string folderName)
        {
            var todayStr = DateTime.Today.ToString("yyyyMMdd"); 
             
            var publishPath = folderName;
            var publishPathDirectoryInfo = new DirectoryInfo(publishPath);
            var zipFileName = string.Format(ZipFileFormat, publishPathDirectoryInfo.Name, todayStr);
            var zipFileFullName = Path.Combine(publishPathDirectoryInfo.Parent.FullName, zipFileName);
            if (File.Exists(zipFileFullName))
                File.Delete(zipFileFullName);
            zip.CreateZip(zipFileFullName, publishPath, true, string.Empty);
            ZipFiles.Add(zipFileFullName);
        }

        private void SetupSites()
        {
            // haven't consider DB

            if (Configuration.Current.PublishSites != null && Configuration.Current.PublishSites.Length > 0)
            {
                Status = "Please waiting...";
                foreach (var publishSite in Configuration.Current.PublishSites)
                {
                    //CMS6
                    var cms6RootPath = publishSite.Cms6SiteRootPath;
                    EnsureDirectoryExists(cms6RootPath);
                    var cms6SiteRootPath = Path.Combine(cms6RootPath, "CMS6");
                    EnsureDirectoryExists(cms6SiteRootPath);
                    var cms6ComponentsRootPath = Path.Combine(cms6RootPath, "Components");
                    EnsureDirectoryExists(cms6ComponentsRootPath);
                    if (publishSite.DeleteExists)
                    {
                        Status = "Deleting the files of CMS6.";
                        Directory.Delete(cms6SiteRootPath, true);
                        Status = "Deleting the files of CMS6 Components.";
                        Directory.Delete(cms6ComponentsRootPath, true);
                    }
                    CopyFolder(Configuration.Current.CMS6PublishPath, cms6SiteRootPath);
                    CopyFolder(Configuration.Current.ComponentsPublishPath, cms6ComponentsRootPath);
                    if (!string.IsNullOrEmpty(publishSite.Cms6ConnectionString)) 
                    {
                        // Change Connect String in Web.config
                        var cms6ConnectionStringRegex = @"<add name=" + "\"" + "CmsDbContext" + "\"" + ".*/>";
                        var newCms6ConnectionStringNode = string.Format("<add name=\"CmsDbContext\" connectionString=\"{0}\" providerName=\"System.Data.SqlClient\" />", publishSite.Cms6ConnectionString);
                        var cms6WebConfigFile = Path.Combine(cms6SiteRootPath, "web.config");
                        var allContent = string.Empty;
                        using (var streamReader = new StreamReader(cms6WebConfigFile))
                        {
                            allContent = streamReader.ReadToEnd();
                        }
                        allContent = Regex.Replace(allContent, cms6ConnectionStringRegex, newCms6ConnectionStringNode);
                        using (var streamWriter = new StreamWriter(cms6WebConfigFile, false))
                        {
                            streamWriter.Write(allContent);
                            streamWriter.Flush();
                        }
                    }
                    // We can run the .bat file to setup folder access permissions

                    var vcmsRootPath = publishSite.VcmsSiteRootPath;
                    EnsureDirectoryExists(vcmsRootPath);
                    if (publishSite.DeleteExists)
                        Directory.Delete(vcmsRootPath, true);
                    CopyFolder(Configuration.Current.VCMSPublishPath, vcmsRootPath);
                    if (!string.IsNullOrEmpty(publishSite.VcmsConnectionString))
                    {
                        // Change Connect String in Web.config
                        var vcmsConnectionStringRegex = @"<add name=" + "\"" + "CmsDbContext" + "\"" + ".*/>";
                        var newVcmsConnectionStringNode = string.Format("<add name=\"CmsDbContext\" connectionString=\"{0}\" providerName=\"System.Data.SqlClient\" />", publishSite.VcmsConnectionString);
                        var vcmsWebConfigFile = Path.Combine(vcmsRootPath, "web.config");
                        var allContent = string.Empty;
                        using (var streamReader = new StreamReader(vcmsWebConfigFile))
                        {
                            allContent = streamReader.ReadToEnd();
                        }
                        allContent = Regex.Replace(allContent, vcmsConnectionStringRegex, newVcmsConnectionStringNode);
                        using (var streamWriter = new StreamWriter(vcmsWebConfigFile, false))
                        {
                            streamWriter.Write(allContent);
                            streamWriter.Flush();
                        }
                    }
                    // We can run the .bat file to setup folder access permissions
                }
                Status = "Setup sites successfully.";
                MessageBox.Show("Setup sites successfully.");
            } 
        }

        private void PrepareUploadtoGold()
        {
            var goldFtpPath = Configuration.Current.GoldFtpPath;
            EnsureDirectoryExists(goldFtpPath);
            var todayGoldFtpPath = Path.Combine(goldFtpPath, DateTime.Today.ToString("yyyyMMdd"));
            EnsureDirectoryExists(todayGoldFtpPath);

            // haven't consider DB
            foreach (var file in ZipFiles)
            {
                var fileName = Path.GetFileName(file);
                var goldFileName = Path.Combine(todayGoldFtpPath, fileName);
                File.Copy(fileName, goldFileName, true);
            }
            MessageBox.Show("Prepare upload files to Gold successfully.");
        }

        private void CopyFolder(string sourceFolder, string destFolder, bool deleteAll = true, bool recursive = true, string searchPattern = "*.*")
        {
            if (Directory.Exists(sourceFolder))
            {
                if (deleteAll && Directory.Exists(destFolder))
                    Directory.Delete(destFolder, true);

                if (!Directory.Exists(destFolder))
                    Directory.CreateDirectory(destFolder);

                searchPattern = string.IsNullOrEmpty(searchPattern) ? "*.*" : searchPattern;
                var allFiles = Directory.GetFiles(sourceFolder, searchPattern, SearchOption.TopDirectoryOnly);
                foreach (var file in allFiles)
                {
                    File.Copy(file, Path.Combine(destFolder, Path.GetFileName(file)), true);
                }

                if (recursive)
                {
                    var subDirectories = Directory.GetDirectories(sourceFolder);
                    foreach (var subDirectory in subDirectories)
                    {
                        var subDirectoryInfo = new DirectoryInfo(subDirectory);
                        var subDestDirectory = Path.Combine(destFolder, subDirectoryInfo.Name);
                        CopyFolder(subDirectory, subDestDirectory, deleteAll, recursive, searchPattern);
                    }
                }
            }
        }
        #endregion

        #region INotifyPropertyChanged Members

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}
